﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Web.Caching;

namespace BlogEngine.Core
{
    /// <summary>
    /// 网站访问统计
    /// </summary>
    public static class Counter
    {
        static string FilePth = string.Empty;
		static string ErrorLogFilePth = string.Empty;
        /// <summary>
        /// HitsArr[0]表示总的点击数,
        /// HitsArr[1]标识昨天的点击数,
        /// HitsArr[2]表示今天的点击数,
        /// HitsArr[3]表示总的访问数(PV?),
        /// HitsArr[4]标识昨天的访问数(PV?),
        /// HitsArr[5]表示今天的访问数(PV?)
        /// </summary>
        private static int[] HitsArr = { -1, 0, 0, 0, 0, 0 };

        #region 构造函数
        /// <summary>
		/// 构造函数
		/// </summary>
		static Counter()
		{
			if(FilePth.Length == 0)
			{
				HttpContext ctx =HttpContext.Current;
				FilePth = ctx.Server.MapPath("~/App_Data/Count.txt");
                ErrorLogFilePth = ctx.Server.MapPath("~/App_Data/CountLog.txt");
			}
			LoadHits();
		}
		#endregion

		#region CacheItemRemovedCallback对象
		/// <summary>
		/// CacheItemRemovedCallback对象
		/// </summary>
		private static CacheItemRemovedCallback onRemove = null;
		#endregion

		#region 缓存名称
		/// <summary>
		/// 缓存名称
		/// </summary>
		private const string  CacheName="UpdateHitsForExpired";
		#endregion

		#region LockForAddHits锁
		/// <summary>
		/// LockForAddHits锁
		/// </summary>
		private static object LockForAddHits=new object();
		#endregion

		#region 将累计点击数保存到全局变量，当它达到一定量时保存到文本文件，并清空
		/// <summary>
		/// 将累计点击数保存到全局变量，当它达到一定量时保存到文本文件，并清空
		/// </summary>
		public static void AddHits()
		{
            bool visited = false;//在指定时间范围内是否访问过
            if (null != HttpContext.Current)
            {
                if (null != HttpContext.Current.Request.Cookies["visited"])
                {
                    visited = HttpContext.Current.Request.Cookies["visited"].Value.ToLower() == "true";
                }
            }

			lock(LockForAddHits)
			{
				if( Hits != 0 )
				{
                    Add(visited);
					if(Hits > 200 )
					{
						//--移除						
						HttpRuntime.Cache.Remove(CacheName);
					}
				}
				else
				{
					onRemove = new CacheItemRemovedCallback(ItemRemovedFromCache);
					HttpRuntime.Cache.Insert(
						CacheName,
						"This Object For Expired", 
						null,
						DateTime.Now.AddSeconds(60*30) ,
						TimeSpan.Zero,
						System.Web.Caching.CacheItemPriority.Normal,
						onRemove
						);
                    Add(visited);					
				}
			}

            if (!visited && null != HttpContext.Current)
            {
                HttpCookie newcookie = new HttpCookie("visited");
                newcookie.Value = "true";
                newcookie.Expires = DateTime.Now.AddDays(0.5);
                HttpContext.Current.Response.AppendCookie(newcookie);
            }
		}
		#endregion			

		#region 保存到文本文件
		/// <summary>
		/// 保存到文本文件
		/// </summary>
		/// <param name="AllId"></param>
		private static void SaveHitsToFile(int hits, int visitors)
		{
			string hitsinfo = string.Empty;			

			DateTime LastWriteTime = File.GetLastWriteTime(FilePth);
			if((DateTime.Today - LastWriteTime).TotalDays >0 )
			{
				//--表示今天第一次写数据
				HitsArr[1] = HitsArr[2];//--将当前累计的点击数赋给昨天的点击数
				HitsArr[2] = hits;//--设置今天的点击数
                HitsArr[4] = HitsArr[5];//--将当前累计的访问数赋给昨天的访问数
                HitsArr[5] = visitors;//--设置今天的访问数
				using(StreamWriter streamWriter = new StreamWriter(FilePth,false) )
				{
                    streamWriter.Write(string.Format("{0},{1},{2},{3},{4},{5}", 
                        HitsArr[0] + hits, HitsArr[1], hits,
                        HitsArr[3] + visitors, HitsArr[4], visitors));
					streamWriter.Flush();
				}
			}
			else
			{
				using(StreamWriter streamWriter = new StreamWriter(FilePth,false) )
				{
                    streamWriter.Write(string.Format("{0},{1},{2},{3},{4},{5}",
                        HitsArr[0] + hits, HitsArr[1], HitsArr[2] + hits,
                        HitsArr[3] + visitors, HitsArr[4], HitsArr[5] + visitors));
					streamWriter.Flush();
				}
			}
		}
		#endregion		

		#region ItemRemovedFromCacheHits锁
		/// <summary>
		/// ItemRemovedFromCacheHits锁
		/// </summary>
		private static object LockForItemRemovedFromCacheHits=new object();
		#endregion
		
		#region 当缓存被移除或过期是触发的回调事件
		/// <summary>
		/// 当缓存被移除或过期是触发的回调事件
		/// </summary>
		/// <param name="key"></param>
		/// <param name="value"></param>
		/// <param name="reason"></param>
		private static void ItemRemovedFromCache(string key, object value,CacheItemRemovedReason reason)
		{
			try
			{
				#region 清空并写到文本文件
				int  _hits = 0;
                int _visitors = 0;
				lock(LockForItemRemovedFromCacheHits)
				{
					_hits = Hits;
					HitsArr[0] += _hits;
					HitsArr[2] += _hits;
					Hits = 0;

                    _visitors = Visitors;
                    HitsArr[3] += _visitors;
                    HitsArr[5] += _visitors;
                    Visitors = 0;
				}
				if(_hits == 0)
				{
					return;
				}
				else
				{
					SaveHitsToFile(_hits, _visitors);
				}				
				#endregion
			}
			catch(Exception ex)
			{
				using(StreamWriter streamWriter = new StreamWriter(ErrorLogFilePth,false) )
				{
					streamWriter.Write(string.Format("时间:{0}\r\n描述信息：{1}\r\n",DateTime.Now,ex.Message));
					streamWriter.Flush();
				}
			}
		}
		#endregion

        #region 获取所有的点击数、访问数
        /// <summary>
		/// 获取所有的点击数
		/// </summary>
		public static  int AllHits
		{
			get
			{
				return HitsArr[0] + Hits;
			}
		}
        /// <summary>
        /// 获取所有的访问数
        /// </summary>
        public static int AllVisitors
        {
            get
            {
                return HitsArr[3] + Visitors;
            }
        }
		#endregion

        #region 获取昨天点击数、访问数
        /// <summary>
		/// 获取昨天点击数
		/// </summary>
        public static int YesterdayHits
		{
			get
			{
				return HitsArr[1];
			}
		}
        /// <summary>
        /// 获取昨天访问数
        /// </summary>
        public static int YesterdayVisitors
        {
            get
            {
                return HitsArr[4];
            }
        }
		#endregion		

		#region 获取今天点击数、访问数
		/// <summary>
		/// 获取今天点击数
		/// </summary>
        public static int TodayHits
		{
			get
			{
				return HitsArr[2] + Hits;
			}
		}
        /// <summary>
        /// 获取今天访问数
        /// </summary>
        public static int TodayVisitors
        {
            get
            {
                return HitsArr[5] + Visitors;
            }
        }
		#endregion

        #region 加载点击数、访问数
        /// <summary>
		/// 加载点击数
		/// </summary>
		private static void LoadHits()
		{
			if(HitsArr[0] == -1)
			{
				if( ! File.Exists(FilePth) )
				{
					//--第一次使用
                    using (StreamWriter streamWriter = new StreamWriter(FilePth))
					{
                        streamWriter.Write(string.Format("{0},{1},{2},{3},{4},{5}", 0, 0, 0, 0, 0, 0));
						streamWriter.Flush();
					}
                    HitsArr[0] = HitsArr[1] = HitsArr[2] = HitsArr[3] = HitsArr[4] = HitsArr[5] = 0;
                    //HitsArr[0] = 0;
                    //HitsArr[1] = 0;
                    //HitsArr[2] = 0;
				}
				else
				{
					string hitsinfo = string.Empty;
                    using (StreamReader objStreamReader = new StreamReader(FilePth)) 
					{
						hitsinfo = objStreamReader.ReadLine();
					}
					if(hitsinfo != "")
					{
						string[] arr = hitsinfo.Split(',');
						HitsArr[0] = Convert.ToInt32(arr[0]);
						HitsArr[1] = Convert.ToInt32(arr[1]);
						HitsArr[2] = Convert.ToInt32(arr[2]);
                        HitsArr[3] = Convert.ToInt32(arr[3]);
                        HitsArr[4] = Convert.ToInt32(arr[4]);
                        HitsArr[5] = Convert.ToInt32(arr[5]);
					}
					else
					{
                        HitsArr[0] = HitsArr[1] = HitsArr[2] = HitsArr[3] = HitsArr[4] = HitsArr[5] = 0;
						//HitsArr[1] = 0;
						//HitsArr[2] = 0;
					}
				}
			}
		}
		#endregion

		#region 累计的点击数、访问数
		/// <summary>
		/// 累计的点击数
		/// </summary>
		private static int _Hits = 0;
        /// <summary>
        /// 累计的访问数
        /// </summary>
        private static int _visitors = 0;
		#endregion

        #region 获取累计的点击数、访问数
        /// <summary>
        /// 获取累计的访问数
		/// </summary>
        private static int Visitors
		{
			get
			{
				return	_visitors;
			}
			set
			{
                _visitors = value;
			}
		}
        /// <summary>
        /// 获取累计的点击数
        /// </summary>
        private static int Hits
        {
            get
            {
                return _Hits;
            }
            set
            {
                _Hits = value;
            }
        }
		#endregion

		#region 累加
		/// <summary>
		/// 累加
		/// </summary>
        /// <param name="visited">在指定时间范围内是否已经访问过</param>
		private static void Add(bool visited)
		{
            _Hits += 1;
            if (!visited)
                _visitors += 1;
		}
		#endregion	
    }
}
